#include "Assistant.h"
#include "OBJParser.h"
#include <string>
#include <iostream>
#include <fstream>

using namespace std;

CObjParser::CObjParser()
{
	m_Verts = new std::vector<CVector>();
	m_VTextures = new std::vector<CVector>();
	m_Normals = new std::vector<CVector>();
	m_Faces = new std::vector<SFace>();
}

CObjParser::~CObjParser()
{
	delete m_Verts;
	delete m_VTextures;
	delete m_Normals;
	delete m_Faces;
}

CMesh CObjParser::ParseObj(const std::string _fileName)
{
	// Open file
	ifstream objFile(_fileName.c_str());

	if(objFile.fail())
	{
		cout << "[OBJ] Nie moge otworzyc pliku " << _fileName.c_str()  << endl;
		return CMesh();
	}

	// Extract verts, normals, textures, and faces
	
	//vector finalVerts, finalNorms, finalTextures;
	//vector finalFaces;

	string line;
	int hashIndex = 0;

	// Visit each line of the obj file
	while(getline(objFile, line))
	{
		// Verts
		if(line[0] == 'v' && line[1] == ' ')
		{
			CVector vec = CVector();
			string lineVals = line.substr(2);
			float val;

			string val0 = lineVals.substr(0, lineVals.find(' '));
			val = (float)atof(val0.c_str());
			vec.SetX(val);

			string val1 = lineVals.substr(val0.length() + 1, 
								lineVals.find(' '));
			val = (float)atof(val1.c_str());
			vec.SetY(val);

			string val2 = lineVals.substr(lineVals.find_last_of(' ') + 1);
			val = (float)atof(val2.c_str());
			vec.SetZ(val);

			m_Verts->push_back(CVector(vec));
		}


		// VT
		else if(line[0] == 'v' && line[1] == 't' && line[2] == ' ')
		{
			CVector vec = CVector();
			string lineVals = line.substr(3);
			float val;

			string val0 = lineVals.substr(0, lineVals.find(' '));
			val = (float)atof(val0.c_str());
			vec.SetX(val);

			string val1 = lineVals.substr(val0.length() + 1, 
								lineVals.find(' '));
			val = (float)atof(val1.c_str());
			vec.SetY(val);

			m_VTextures->push_back(CVector(vec));
		}

		// Normals
		else if(line[0] == 'v' && line[1] == 'n' && line[2] == ' ')
		{
			CVector vec = CVector();
			string lineVals = line.substr(3);
			float val;

			string val0 = lineVals.substr(0, lineVals.find(' '));
			val = (float)atof(val0.c_str());
			vec.SetX(val);

			string val1 = lineVals.substr(val0.length() + 1, 
								lineVals.find(' '));
			val = (float)atof(val1.c_str());
			vec.SetY(val);

			string val2 = lineVals.substr(lineVals.find_last_of(' ') + 1);
			val = (float)atof(val2.c_str());
			vec.SetZ(val);

			m_Normals->push_back(CVector(vec));
		}


		// Faces
		else if(line[0] == 'f' && line[1] == ' ')
		{
			string lineVals = line.substr(2);
			//float val;

			string val0 = lineVals.substr(0, lineVals.find_first_of(' '));

			// If the value for this face includes texture and/or 
			// normal, parse them out
			if(val0.find('/') >= 0)
			{
				CVector vertsVec = CVector();
				CVector vtVec = CVector();
				CVector normVec = CVector();
				float val;
				// Get first group of values
				string g1 = val0.substr(0, val0.find(' '));
        
				// Get second group of values
				string g2 = line.substr(line.find(' ') + 2);
				g2 = g2.substr(g2.find(' ') + 1);
				g2 = g2.substr(0, g2.find(' '));

				string g3 = line.substr(line.find_last_of(' ') + 1);

				// G1
				string s1 = g1.substr(0, g1.find('/'));
				string gs1 = g1.substr(g1.find('/') + 1, g1.length() - g1.find('/'));
				string s2 = gs1.substr(0, gs1.find('/'));
				string gs2 = gs1.substr(gs1.find('/') + 1, gs1.length() - gs1.find('/'));
				string s3 = gs2.substr(0, gs2.find('/'));
				
				val = (float) atof(s1.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vertsVec.SetX(val);

				val = (float) atof(s2.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vtVec.SetX(val);

				val = (float) atof(s3.c_str());

				if ( !FEQUAL(val, 0.0f) )
					normVec.SetX(val);
				// G1 END

				// G2
				s1 = g2.substr(0, g2.find('/'));
				gs1 = g2.substr(g2.find('/') + 1, g2.length() - g2.find('/'));
				s2 = gs1.substr(0, gs1.find('/'));
				gs2 = gs1.substr(gs1.find('/') + 1, gs1.length() - gs1.find('/'));
				s3 = gs2.substr(0, gs2.find('/'));
				
				val = (float) atof(s1.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vertsVec.SetY(val);

				val = (float) atof(s2.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vtVec.SetY(val);

				val = (float) atof(s3.c_str());

				if ( !FEQUAL(val, 0.0f) )
					normVec.SetY(val);
				// G2 END

				// G3
				s1 = g3.substr(0, g3.find('/'));
				gs1 = g3.substr(g3.find('/') + 1, g3.length() - g3.find('/'));
				s2 = gs1.substr(0, gs1.find('/'));
				gs2 = gs1.substr(gs1.find('/') + 1, gs1.length() - gs1.find('/'));
				s3 = gs2.substr(0, gs2.find('/'));
				
				val = (float) atof(s1.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vertsVec.SetZ(val);

				val = (float) atof(s2.c_str());

				if ( !FEQUAL(val, 0.0f) )
					vtVec.SetZ(val);

				val = (float) atof(s3.c_str());

				if ( !FEQUAL(val, 0.0f) )
					normVec.SetZ(val);
				// G3

				m_Faces->push_back(SFace(vertsVec, vtVec, normVec));
			}
			else
			{

			}
			
		}
	} 

	objFile.close();

	CTriangle *tris = new CTriangle[m_Faces->size()];
	SFace face;


	for (int i = 0; i < (int) m_Faces->size(); i++)
	{
		face = (*m_Faces)[i];
		
		tris[i].SetA((*m_Verts)[ (int) face.m_Verts->GetX() - 1] );				// A
		tris[i].SetB((*m_Verts)[ (int) face.m_Verts->GetY() - 1] );				// B
		tris[i].SetC((*m_Verts)[ (int) face.m_Verts->GetZ() - 1] );				// C
		tris[i].SetNormal((*m_Normals)[ (int) face.m_Normals->GetX() - 1]);		// Normal vector
		tris[i].SetColor(CLightIntensity(0.1f, 0.2f, 0.7f));					// Default color
		tris[i].CheckNormal();													// IMPORTANT!		
	}

	std::cout << "Mesh loaded successfully..." << std::endl;

	return CMesh(tris, m_Faces->size());
}